#define BLINKER_WIFI
#define BLINKER_MIOT_LIGHT

#include <Blinker.h>
#include <light.h>
#include <XOutput.h>
#include <Xinput.h>

#define BLINKER_KEY "1187a611741b"
#define WIFI_SSID "6666666666666"
#define WIFI_PASSWARD "18551850830"
#define VERSION 1
#define TIME_SE_OPERATION 1000
#define TIME_KEY_FILTER 5

Light light(14, 13, 12, true, VERSION, [](unsigned long ms) {Blinker.delay(ms);});
XOutput led(2, false, [](unsigned long ms) {Blinker.delay(ms);}), beep(5, true, [](unsigned long ms) {Blinker.delay(ms);});
XInput keyLeft(4), keyMid(2), keyRight(0);

void setup()
{
  led.init();
  light.init();
  keyLeft.init();
  keyRight.init();
  Serial.begin(74480);
  
  WiFi.setSleepMode(WIFI_LIGHT_SLEEP, 500);

  BLINKER_DEBUG.stream(Serial);
  BLINKER_DEBUG.debugAll();
  Blinker.begin(BLINKER_KEY, WIFI_SSID, WIFI_PASSWARD);
  Blinker.attachData([] (const String & data) {
    Blinker.print("ip", WiFi.localIP().toString());
  });
  BlinkerMIOT.attachPowerState([] (const String & state) {
    BlinkerMIOT.powerState(state);
    BlinkerMIOT.print();
    if (state == BLINKER_CMD_ON) {
      Blinker.print("cmd", "on");
      led.on();
      light.start().on(TIME_SE_OPERATION).reset(TIME_SE_OPERATION).finish();
      led.off();
    }
    else if (state == BLINKER_CMD_OFF) {
      Blinker.print("cmd", "off");
      led.on();
      light.start().off(TIME_SE_OPERATION).reset(TIME_SE_OPERATION).finish();
      led.off();
    }
  });
  BlinkerMIOT.attachMode([] (uint8_t mode) {
    BlinkerMIOT.mode(mode);
    BlinkerMIOT.print();
    if (mode == BLINKER_CMD_MIOT_TV) {
      Blinker.print("mode", "TV");
      led.on();
      light.start().leftOff(TIME_SE_OPERATION).leftReset(TIME_SE_OPERATION).finish();
      led.off();
    }
  });
  BlinkerMIOT.attachQuery([] (int32_t queryCode) {
    BlinkerMIOT.print();
  });
}

inline void waitKeyRelease()
{
  beep.on();
  while(keyLeft.read() || keyMid.read() || keyRight.read())
  {
    Blinker.delay(TIME_KEY_FILTER);
  }
  beep.off();
}

void loop()
{
  static enum {
    START,
    CHECK_CONNECT,
    CHECK_KEY_PRESS,
    RESET_ALL,
    SET_LEFT_ON,
    SET_LEFT_DEFAULT,
    SET_LEFT_OFF,
    SET_LEFT_TEST,
    SET_RIGHT_ON,
    SET_RIGHT_DEFAULT,
    SET_RIGHT_OFF,
    SET_RIGHT_TEST,
    END,
  } loopDFA = START;

  switch (loopDFA)
  {
    case START:
      loopDFA = keyLeft.read() || keyRight.read() ? CHECK_KEY_PRESS : CHECK_CONNECT;
      break;
    
    case CHECK_CONNECT:
      led.setState(!Blinker.connected());
      loopDFA = END;
      break;

    case CHECK_KEY_PRESS:
      keyMid.init();
      Blinker.delay(TIME_KEY_FILTER);
      if(!keyLeft.read() && !keyRight.read())
      {
        loopDFA = CHECK_CONNECT;
        break;
      }
      else if(keyLeft.read() && keyRight.read())
      {
        waitKeyRelease();
        loopDFA = RESET_ALL;
        break;
      }
      else if(keyMid.read())
      {
        if(keyLeft.read())
        {
          waitKeyRelease();
          loopDFA = SET_LEFT_ON;
          break;
        }
        else if(keyRight.read())
        {
          waitKeyRelease();
          loopDFA = SET_RIGHT_ON;
          break;
        }
      }
      break;

    case RESET_ALL:
      beep.blink(2);
      light.dataReset();
      loopDFA = END;
      break;
    
    case SET_LEFT_ON:
      if(keyMid.read())
      {
        loopDFA = SET_LEFT_DEFAULT;
      }
      else if(keyRight.read())
      {
        if(light.data.leftOn < 180)
        {
          light.data.leftOn++;
        }
      }
      else if(keyLeft.read())
      {
        if(light.data.leftOn > 1)
        {
          light.data.leftOn--;
        }
      }
      waitKeyRelease();
      break;
    
    case SET_LEFT_DEFAULT:
      if(keyMid.read())
      {
        loopDFA = SET_LEFT_OFF;
      }
      else if(keyRight.read())
      {
        if(light.data.leftDefault < 180)
        {
          light.data.leftDefault++;
        }
      }
      else if(keyLeft.read())
      {
        if(light.data.leftDefault > 1)
        {
          light.data.leftDefault--;
        }
      }
      waitKeyRelease();
      break;
    
    case SET_LEFT_OFF:
      if(keyMid.read())
      {
        light.data.write();
        loopDFA = SET_LEFT_TEST;
      }
      else if(keyRight.read())
      {
        if(light.data.leftOff < 180)
        {
          light.data.leftOff++;
        }
      }
      else if(keyLeft.read())
      {
        if(light.data.leftOff > 1)
        {
          light.data.leftOff--;
        }
      }
      waitKeyRelease();
      break;
    
    case SET_LEFT_TEST:
      beep.blink(2);
      light.start()
        .leftReset(TIME_SE_OPERATION)
        .leftOn(TIME_SE_OPERATION)
        .leftReset(TIME_SE_OPERATION)
        .leftOff(TIME_SE_OPERATION)
        .leftReset(TIME_SE_OPERATION)
        .finish();
      loopDFA = END;
      break;
    
    case SET_RIGHT_ON:
      if(keyMid.read())
      {
        loopDFA = SET_RIGHT_DEFAULT;
      }
      else if(keyRight.read())
      {
        if(light.data.rightOn < 180)
        {
          light.data.rightOn++;
        }
      }
      else if(keyLeft.read())
      {
        if(light.data.rightOn > 1)
        {
          light.data.rightOn--;
        }
      }
      waitKeyRelease();
      break;
    
    case SET_RIGHT_DEFAULT:
      if(keyMid.read())
      {
        loopDFA = SET_RIGHT_OFF;
      }
      else if(keyRight.read())
      {
        if(light.data.rightDefault < 180)
        {
          light.data.rightDefault++;
        }
      }
      else if(keyLeft.read())
      {
        if(light.data.rightDefault > 1)
        {
          light.data.rightDefault--;
        }
      }
      waitKeyRelease();
      break;
    
    case SET_RIGHT_OFF:
      if(keyMid.read())
      {
        light.data.write();
        loopDFA = SET_RIGHT_TEST;
      }
      else if(keyRight.read())
      {
        if(light.data.rightOff < 180)
        {
          light.data.rightOff++;
        }
      }
      else if(keyLeft.read())
      {
        if(light.data.rightOff > 1)
        {
          light.data.rightOff--;
        }
      }
      waitKeyRelease();
      break;
    
    case SET_RIGHT_TEST:
      beep.blink(2);
      light.start()
        .rightReset(TIME_SE_OPERATION)
        .rightOn(TIME_SE_OPERATION)
        .rightReset(TIME_SE_OPERATION)
        .rightOff(TIME_SE_OPERATION)
        .rightReset(TIME_SE_OPERATION)
        .finish();
      loopDFA = END;
      break;

    default:
    case END:
      led.init();
      Blinker.run();
      loopDFA = START;
      break;
  }
}
